/* === LICENSE INFO ===
 * This source file is subject to the GPLv3 license that is bundled with this
 * package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://www.gnu.org/licenses/gpl.txt
 * === end of LICENSE INFO === */

/*==============================================================================
  File Name   : MetaInfoUtil.hpp
  Description : This file defines MetaInfo that can be attached to many other
                classes. It also declares utility functions for manipulating
                MetaInfo.

  Created on  : 2010-06-22
  Updated on  : 2010-06-24
  Updated by  : Lee Shiou Ming

  Cautions    : (important notes)
  ============================================================================*/

#ifndef METAINFOUTIL_HPP_
#define METAINFOUTIL_HPP_

#include <string>
#include <stdexcept>

/**
 * @brief Initial values for various meta data.
 */
#define INIT_VALUE_MAJOR_VERSION 1
#define INIT_VALUE_MINOR_VERSION 0
#define INIT_VALUE_META_ID       0

/**
 * @brief Max values according to type range.
 */
#define META_VERSION_NUM_MAXVAL  SHRT_MAX


/**
 * @brief All gUtil modules will be wrapped within gUtil namespace.
 */
namespace gUtil
{
/**
 * @brief Namespace for GMetaInfo module.
 */
namespace GMetaInfo
{
    /**
     * @brief Represents meta version number, part of MetaInfo.
     */
    struct MetaVersion
    {
        MetaVersion()
        {
            m_majorVerNum = INIT_VALUE_MAJOR_VERSION;
            m_minorVerNum = INIT_VALUE_MINOR_VERSION;
        }

        unsigned short m_majorVerNum;
        unsigned short m_minorVerNum;
    };  // end of struct MetaVersion


    /**
     * @brief Contains general meta info such as ID and version number, which
     *        can be reused by attaching to many other classes.
     */
    struct MetaInfo
    {
        MetaInfo()
        {
            m_id = INIT_VALUE_META_ID;
        }

        unsigned int m_id;
        MetaVersion m_version;
    };  /* end of struct MetaInfo */


    /**
     * @brief Call this function for each major change.
     *
     * Increase metainfo's major version number by 1, and reset minor version
     * number to 0.
     *
     * @param _metaInfo
     * [IN/OUT] Client's metainfo which version number will be adjust.
     *
     * @throw MetaInfoException
     */
    void setMetaVersionMajorChange(MetaInfo& _metaInfo);

    /**
     * @brief Call this function for each minor change.
     *
     * Increase metainfo's minor version number by 1.
     *
     * @param _metaInfo
     * [IN/OUT] Client's metainfo which version number will be adjust.
     *
     * @throw MetaInfoException
     */
    void setMetaVersionMinorChange(MetaInfo& _metaInfo);

    /**
     * @brief Construct a string representation of MetaVersion.
     *
     * @param _metaInfo
     * [IN] Metainfo which contains the target MetaVersion.
     * @param _metaVersionStr
     * [OUT] MetaVersion string <major_version>.<minor_version>.
     */
    void getMetaVersionString(const MetaInfo& _metaInfo,
            std::string& _metaVersionStr);

    /**
     * @brief Construct a string representation of MetaVersion.
     *
     * @param _metaVersion
     * [IN] Target MetaVersion.
     * @param _metaVersionStr
     * [OUT] MetaVersion string <major_version>.<minor_version>.
     */
    void getMetaVersionString(const MetaVersion& _metaVersion,
            std::string& _metaVersionStr);

    /**
     * @brief Gives MetaInfo client a chance to handle meta exceptions
     *        differently.
     */
    class MetaInfoException : public std::runtime_error
    {
    public:
        /**
         * @brief Constructor that allows client to supply an error message.
         *
         * @param _errMessage
         * [IN] Error message that describes the exception.
         */
        MetaInfoException(const std::string& _errMessage)
        :
            std::runtime_error("MetaInfoException: " + _errMessage)
        {
        }
    };  /* end of class MetaInfoException */

}  /* end of namespace GMetaInfo */
}  /* end of namespace gUtil */

#endif /* METAINFOUTIL_HPP_ */
